package com.gitee.wsl.common.ui.draw.node


import androidx.compose.ui.graphics.drawscope.DrawScope
import com.gitee.wsl.common.ui.base.ColorOrBrush
import com.gitee.wsl.common.ui.draw.api.HasChildren
import com.gitee.wsl.common.ui.draw.api.HasFill
import com.gitee.wsl.common.ui.draw.api.HasStroke
import com.gitee.wsl.common.ui.draw.style.HierarchicalNodeStyle
import com.gitee.wsl.common.ui.draw.style.NodeStyle
import com.gitee.wsl.common.ui.draw.type.TextHAlign
import com.gitee.wsl.common.ui.draw.type.TextVAlign


/**
 * The base class of each element of the viz hierarchy.
 * Keeps a reference to the parent node.
 */
 abstract class Node : NodeStyle {

     var parent: HasChildren? = null
        set(value) {
            field = value
            (parent as? NodeStyle).let { style.parent = it  }
        }

    /**
     * This property allows to put classes on node to allows some selection like
     * in the DOM through classes selectors.
     *
     * It's use is experimental you can use it but without the garanty that it will
     * be there in future versions of the library.
     */
    @ExperimentalD2V
     var classes: String? = null

    /**
     * Specifies whether the item is visible. When set to false, the item won’t be drawn.
     *
     * default to true.
     */
     var visible: Boolean = true

    /**
     * Removes the node from the hierarchy.
     */
     fun remove() {
        parent?.remove(this)
    }

    val style: HierarchicalNodeStyle = HierarchicalNodeStyle(parent as? NodeStyle)

    override var fill: ColorOrBrush? by style::fill

    override var strokeColor: ColorOrBrush? by style::strokeColor

    override var dashedLine: DoubleArray? by style::dashedLine

    override var strokeWidth: Float? by style::strokeWidth

    override var textColor: ColorOrBrush? by style::textColor

    override var hAlign: TextHAlign by style::hAlign

    override var vAlign: TextVAlign by style::vAlign


    internal open var invalidateListener: (() -> Unit)? = null

    fun invalidate() {
        invalidateListener?.invoke()
    }

    abstract fun DrawScope.draw()

}

val Node.hasStyles
    get() = when (this) {
        is HasStroke -> strokeColor != null || strokeWidth != null || dashedLine != null
        is HasFill -> fill != null
        else -> false
    }


abstract class AbstractNode:Node(){

    override fun DrawScope.draw(){
        fill?.let {
            drawFill(it)
        }
        strokeColor?.let {
            drawOutLine(it)
        }
    }

    abstract fun DrawScope.drawOutLine(colorOrBrush: ColorOrBrush)

    abstract fun DrawScope.drawFill(colorOrBrush: ColorOrBrush)

}